/**
 * createStore(reducer, preloadedState, enhancer)
 * { getState, dispatch, subscribe }
 */

function createStore (reducer, preloadedState, enhancer) {
    // 约束 reducer 参数类型，必须为函数类型
    if (typeof reducer !== 'function') throw new Error('reducer 必须是函数')
    // 判断 enhancer 有没有传递
    if (typeof enhancer !== 'undefined') {
        // 判断 enhancer 是不是一个函数
        if (typeof enhancer !== 'function') throw new Error('enhancer 必须是函数')
        return enhancer(createStore)(reducer, preloadedState)
    }
    // store 对象中存储的状态
    var currentState = preloadedState
    // 存放订阅者函数
    var currentListeners = []

    // 获取状态
    function getState () {
        return currentState
    }
    // 触发 action 
    function dispatch (action) {
        // 判断 action 是否是对象
        if (!isPlainObject(action)) throw new Error('action 必须是对象')
        // 判断对象中是否具有 type 属性
        if (typeof action.type === 'undefined') throw new Error('action 必须有 type 属性')
        currentState = reducer(currentState, action)
        // 循环数组  调用订阅者
        for (let i = 0; i < currentListeners.length; i++) {
            // 获取订阅者
            var listener = currentListeners[i]
            // 调用订阅者
            listener()
        }
    }
    // 订阅状态
    function subscribe (listener) {
        currentListeners.push(listener)
    }

    return {
        getState,
        dispatch,
        subscribe
    }
}

// 判断 obj 参数是否是对象
function isPlainObject (obj) {
    // 排除基本数据类型和 null
    if (typeof obj !== 'object' || obj === null) return false
    // 区分数组和对象  原型对象对比的方式
    var proto = obj
    while (Object.getPrototypeOf(proto) != null) {
        proto = Object.getPrototypeOf(proto)
    }
    // 判断 obj 的原型类型是否和最顶层的类型相同
    return Object.getPrototypeOf(obj) === proto
}

function applyMiddleware (...middlewares) {
    return function (createStore) {
        return function (reducer, preloadedState) {
            // 获取原生的 store 对象
            var store = createStore(reducer, preloadedState)
            // 阉割版 store 
            var middlewareAPI = {
                getState: store.getState,
                dispatch: store.dispatch
            }
            // 调用中间件的第一层函数  传递阉割版的 store 对象  chain 的元素就是包含 next 形参的函数
            var chain = middlewares.map(middleware => middleware(middlewareAPI))
            // 返回第一个中间件需要执行的函数
            var dispatch = compose(...chain)(store.dispatch)
            return {
                ...store,
                dispatch
            }
        }
    }
}

function compose () {
    var funcs = [...arguments]
    // 此时的 dispatch 就是最后需要执行的 reducer
    return function (dispatch) {
        // 倒序遍历 将最后的 reducer 作为最后一个中间件的 next 参数
        // 最后一个中间件的执行方法作为 倒数第二个中间件的 next 参数 依次遍历
        for (let i = funcs.length - 1; i >= 0; i--) {
            dispatch = funcs[i](dispatch)
        }
        // 遍历结束后 dispatch 就是第一个中间件需要执行的函数
        return dispatch
    }
}

function bindActionCreators (actionCreators, dispatch) {
    var boundActionCreators = {}
    for (let key in actionCreators) {
        boundActionCreators[key] = function () {
            dispatch(actionCreators[key]())
        }
    }
    return boundActionCreators
}

function combineReducers (reducers) {
    // 检查 reducer 类型  必须是函数
    var reducerKeys = Object.keys(reducers)
    for (let i = 0; i < reducerKeys.length; i++) {
        var key = reducerKeys[i]
        if (typeof reducers[key] !== 'function') throw new Error('reducer 必须是函数')
    }
    // 调用一个个小的 reducer 将每个小的 reducer 中返回的状态存储在一个新的大的对象中
    return function (state, action) {
        var nextState = {}
        for (let i = 0; i < reducerKeys.length; i++) {
            var key = reducerKeys[i]
            var reducer = reducers[key]
            // 获取 state 中对应 key 的值  作为 reducer 函数的 state 参数
            var previousStateForKey = state[key]
            nextState[key] = reducer(previousStateForKey, action)
        }
        return nextState
    }
}